package controllers

import java.nio.file.Files
import config.{Global, MyAwait, MyFile, MyRow, MyString}
import dao._

import javax.inject.Inject
import play.api.libs.json.Json
import play.api.mvc.{AbstractController, ControllerComponents}
import utils.TableUtils.{genome, pageForm}
import utils.{ExecCommand, TableUtils}

import scala.concurrent.ExecutionContext

class GenomeController @Inject()(genomeDao: GenomeDao,
                                 blockDao: BlockDao,
                                 blockRangeDao: BlockRangeDao,
                                 cc: ControllerComponents)
                                (implicit exec: ExecutionContext) extends AbstractController(cc) with MyAwait with MyFile with MyRow with MyString {

  def genomePage(species: String) = Action { implicit request =>
    Ok(views.html.genome.genomePage(species))
  }

  def genomeInfoPage= Action{implicit request=>
    Ok(views.html.genome.genomeInfoPage())

  }

  def getAllGene(species: String) = Action { implicit request =>
    val page = pageForm.bindFromRequest.get
    val data = TableUtils.genome(species)
    val orderX = TableUtils.dealMapDataByPage(data, page)
    val total = orderX.size
    val tmpX = orderX.slice(page.offset, page.offset + page.limit)
    Ok(Json.obj("rows" -> tmpX, "total" -> total))
  }

  def genePage(id: String) = Action { implicit request =>
    val x = if (id.isInt) {
      genomeDao.getById(id.toInt).toAwait
    } else {
      genomeDao.getByGeneId(id).toAwait
    }
    Ok(views.html.genome.geneInfoPage(x))
  }

  def getSeqs(geneid: String) = Action { implicit request =>
    val cds = s"${Global.samtools} faidx ${Global.path}/blastData/cds/cds.fa $geneid"
    val pep = s"${Global.samtools} faidx ${Global.path}/blastData/pep/pep.fa $geneid"
    val tmpDir = Files.createTempDirectory("tmpDir").toString
    val exec = new ExecCommand
    exec.exect(Array(cds, pep), tmpDir)
    Ok(
      if (exec.isSuccess) {
        val seq = exec.getOutStr.split(">")
        val cdsSeq = seq(1).split("\n").tail.mkString
        val pepSeq = seq.last.split("\n").tail.mkString
        Json.obj("cds" -> cdsSeq, "pep" -> pepSeq)
      } else {
        Json.obj("valid" -> "false", "msg" -> exec.getErrStr)
      })
  }

  def getFpkm(geneid: String) = Action { implicit request =>
    val data = TableUtils.fpkm.get(geneid.trim)
    if(data.isEmpty){
      Ok(Json.obj("valid" ->  "false"))
    }else{
    val plot = data.get.split("\t").map(_.toDouble)
    Ok(Json.obj("header" -> TableUtils.fpkmHeader.tail, "plot" -> plot))
    }
  }

  def getQTLInfo(id:String) =Action{implicit request=>
    val file = s"${Global.path}/config/qtl_gene/$id.txt".toFile
    if(file.exists()){
      val json = file.readLines.map{x=>
         x.split("\t").zipWithIndex.map{y=>y._2.toString -> y._1}.toMap
      }
      val header = "Snp\tSnpChr\tSnpPos\tGene\tGeneChr\tGeneStart\tGeneEnd\tDist\tCisTrans\tBeta\tt-stat\tP\tFDR".split("\t").map(_.trim)

      Ok(Json.obj("qtl" -> json.toSeq,"header" -> header))
    }else{
      Ok(Json.obj("valid" ->  "false"))
    }
  }

  def getInfos(id: Int) = Action { implicit request =>

    val blocks = blockDao.getById(id).toAwait
    var block = "false"
    if (blocks.nonEmpty) {
      block = blocks.head.block
    }

    val genome = genomeDao.getById(id).toAwait
    val species = genome.species
    val geneid = genome.geneid

    val blockRange = blockRangeDao.getByPos(species, genome.chr, genome.start, genome.end).toAwait.map(_.getMapByT())

    val cds = s"${Global.samtools} faidx ${Global.path}/blastData/cds/cds.fa $geneid"
    val pep = s"${Global.samtools} faidx ${Global.path}/blastData/pep/pep.fa $geneid"
    val tmpDir = Files.createTempDirectory("tmpDir").toString
    val exec = new ExecCommand
    exec.exect(Array(cds, pep), tmpDir)
    Ok(
      if (exec.isSuccess) {
        val seq = exec.getOutStr.split(">")
        val cdsSeq = seq(1).split("\n").tail.mkString
        val pepSeq = seq.last.split("\n").tail.mkString
        Json.obj("cds" -> cdsSeq, "pep" -> pepSeq, "block" -> block,
          "blockRange" -> blockRange)
      } else {
        Json.obj("valid" -> "false", "msg" -> exec.getErrStr, "block" -> block,
          "blockRange" -> blockRange)
      })
  }

  def getByGeneIds(geneid: String) = Action.async { implicit request =>
    genomeDao.getByIds(geneid.split(";").map(x => TableUtils.geneIdToID(x))).map { x =>
      val json = x.map(_.getMapByT())
      Ok(Json.toJson(json))
    }
  }


}
